﻿/**
 * @file audio_aac.h
 * Copyright (c) Gaaagaa. All rights reserved.
 * 
 * @author  : Gaaagaa
 * @date    : 2020-02-20
 * @version : 1.0.0.0
 * @brief   : 封装 FDK-AAC 的 API，实现 PCM-S16 音频数据的 AAC 编解码操作。
 */

#ifndef __AUDIO_AAC_H__
#define __AUDIO_AAC_H__

#include "xtypes.h"

////////////////////////////////////////////////////////////////////////////////

/**
 * @enum  xaac_aot_t
 * @brief AAC 编码的音频对象类型 枚举值。
 */
typedef enum xaac_aot_t
{
    XAOT_AAC_LC    = 0x00000002,  ///<   2
    XAOT_AAC_HE    = 0x00000005,  ///<   5
    XAOT_AAC_HE_V2 = 0x0000001D,  ///<  29
    XAOT_AAC_LD    = 0x00000017,  ///<  23
    XAOT_AAC_ELD   = 0x00000027,  ///<  39
    XAOT_MP2_LC    = 0x00000081,  ///< 129
    XAOT_MP2_SBR   = 0x00000084,  ///< 132
} xaac_aot_t;

////////////////////////////////////////////////////////////////////////////////
// aac_encoder_t

/**
 * @enum  xaac_enc_config_t
 * @brief 编码操作使用的配置参数枚举值。
 */
typedef enum xaac_enc_config_t
{
    XAAC_ENC_AOT_AAC_LC    = 0x00000002,  ///<  2
    XAAC_ENC_AOT_AAC_HE    = 0x00000005,  ///<  5
    XAAC_ENC_AOT_AAC_HE_V2 = 0x0000001D,  ///< 29
    XAAC_ENC_AOT_AAC_LD    = 0x00000017,  ///< 23
    XAAC_ENC_AOT_AAC_ELD   = 0x00000027,  ///< 39
    XAAC_ENC_AOT_MP2_LC    = 0x00000081,  ///< 129
    XAAC_ENC_AOT_MP2_SBR   = 0x00000084,  ///< 132
    XAAC_ENC_AOT_AAC_MASK  = 0x000000FF,  ///< AOT mask

    XAAC_ENC_CHANNELORDER  = 0x00000100,  ///< 是否使用 CHANNELORDER 配置（默认使用）
    XAAC_ENC_AFTERBURNER   = 0x00000200,  ///< 是否使用 AFTERBURNER 特性（默认不使用）
    XAAC_ENC_ELDSBR        = 0x00000400,  ///< AOT == XAOT_AAC_ELD 时，是否使用 SBR 模式（默认不使用）

    XAAC_ENC_TMUXMP4_RAW   = 0x00000000,  ///< "as is" access units
    XAAC_ENC_TMUXMP4_ADIF  = 0x00010000,  ///< ADIF bitstream format.
    XAAC_ENC_TMUXMP4_ADTS  = 0x00020000,  ///< ADTS bitstream format.
    XAAC_ENC_TMUXMP4_MCP1  = 0x00060000,  ///< Audio Mux Elements with muxConfigPresent = 1
    XAAC_ENC_TMUXMP4_MCP0  = 0x00070000,  ///< Audio Mux Elements with muxConfigPresent = 0
    XAAC_ENC_TMUXMP4_LOAS  = 0x000A0000,  ///< Audio Sync Stream.
    XAAC_ENC_TMUXMP4_DRM   = 0x000C0000,  ///< Digital Radio Mondial (DRM30/DRM+) bitstream format.
    XAAC_ENC_TMUXMP4_MASK  = 0x000F0000,  ///< TRANSMUX MP4 mask

    XAAC_ENC_VBRMODE_1     = 0x00100000,  ///< Variable bitrate mode, "very low bitrate".
    XAAC_ENC_VBRMODE_2     = 0x00200000,  ///< Variable bitrate mode, "low bitrate".
    XAAC_ENC_VBRMODE_3     = 0x00300000,  ///< Variable bitrate mode, "medium bitrate".
    XAAC_ENC_VBRMODE_4     = 0x00400000,  ///< Variable bitrate mode, "high bitrate".
    XAAC_ENC_VBRMODE_5     = 0x00500000,  ///< Variable bitrate mode, "very high bitrate".
    XAAC_ENC_VBRMODE_MASK  = 0x00F00000,  ///< Variable bitrate mode mask

    XAAC_ENC_DEFAULT = XAAC_ENC_AOT_AAC_LC   |
                       XAAC_ENC_CHANNELORDER |
                       XAAC_ENC_AFTERBURNER  |
                       XAAC_ENC_TMUXMP4_ADTS
} xaac_enc_config_t;

#define XAAC_ENC_GET_AOT(xencfg)        ((XAAC_ENC_AOT_AAC_MASK & (xencfg)))
#define XAAC_ENC_SET_AOT(xencfg, aot)   ((xencfg) = (((xencfg) & ~XAAC_ENC_AOT_AAC_MASK) | (aot)))

#define XAAC_ENC_BITMODE(xencfg, bit)   (0 != ((xencfg) & (bit)))
#define XAAC_ENC_GET_BIT(xencfg, bit)   ((xencfg) & (bit))
#define XAAC_ENC_SET_BIT(xencfg, bit)   ((xencfg) = ((xencfg) |  (bit)))
#define XAAC_ENC_DEL_BIT(xencfg, bit)   ((xencfg) = ((xencfg) & ~(bit)))

#define XAAC_ENC_SETTMUX(xencfg, tmux)  ((xencfg) = (((xencfg) & ~XAAC_ENC_TMUXMP4_MASK) | (tmux)))
#define XAAC_ENC_GETTMUX(xencfg)        ((XAAC_ENC_TMUXMP4_MASK & (xencfg)) >> 16)

#define XAAC_ENC_SET_VBR(xencfg, vbr)   ((xencfg) = (((xencfg) & ~XAAC_ENC_VBRMODE_MASK) | (vbr)))
#define XAAC_ENC_GET_VBR(xencfg)        ((XAAC_ENC_VBRMODE_MASK & (xencfg)) >> 20)

/**
 * @class aac_encoder_t
 * @brief 封装 FDK-AAC 的 API，实现 PCM-S16 音频数据的编码操作。
 */
class aac_encoder_t
{
    // common data types
public:
    typedef x_byte_t *       xaacbuf_t;
    typedef const xaacbuf_t  caacbuf_t;
    typedef x_int16_t *      xpcmbuf_t;
    typedef const xpcmbuf_t  cpcmbuf_t;

    /**
     * @enum  xerrno_table_t
     * @brief 错误码表。
     */
    typedef enum xerrno_table_t
    {
        //======================================
        // open() 接口产生的错误码

        X_ERR_BAD_ARGS              = 0x00000001,  ///< 参数错误
        X_ERR_ENCODER_CREATE        = 0x00000002,  ///< 创建编码器对象失败
        X_ERR_SETPARAM_AOT          = 0x00000011,  ///< 配置 AOT 参数失败
        X_ERR_SETPARAM_SBR          = 0x00000012,  ///< 配置 SBR MODE 失败
        X_ERR_SETPARAM_CHANNEL      = 0x00000013,  ///< 配置 CHANNEL MODE 失败
        X_ERR_SETPARAM_CHNLORDER    = 0x00000014,  ///< 配置 CHANNEL ORDER 失败
        X_ERR_SETPARAM_SAMPRATE     = 0x00000015,  ///< 配置 sample rate 失败
        X_ERR_SETPARAM_TRANSMUX     = 0x00000016,  ///< 配置 TRANSMUX 失败
        X_ERR_SETPARAM_AFTERBURNER  = 0x00000017,  ///< 配置 AFTERBURNER 失败
        X_ERR_SETPARAM_BITRATEMODE  = 0x00000018,  ///< 配置 BITRATEMODE 失败
        X_ERR_SETPARAM_VBRMODE_1    = 0x00000019,  ///< 配置 BITRATEMODE 成 VBRMODE_1 失败
        X_ERR_SETPARAM_BITRATE      = 0x0000001A,  ///< 配置 BITRATE 失败
        X_ERR_ENCODE_FIRSTINIT      = 0x00000021,  ///< 调用编码操作 API 进行编码器初始化 失败
        X_ERR_GET_ENCODER_INFO      = 0x00000022,  ///< 获取编码器信息 失败

        //======================================
        // encode() 接口产生的错误码

        X_ERR_ENCODE_UNOPEN         = 0x00000081,  ///< 编码器未打开
        X_ERR_ENCODE_BADARGS        = 0x00000082,  ///< 输入参数错误
        X_ERR_ENCODE_FAILED         = 0x00000091,  ///< 编码操作失败

        //======================================
    } xerrno_table_t;

    // common invoking
public:
    /**********************************************************/
    /**
     * @brief 获取 xerrno_table_t 中的错误码名称。
     */
    static x_cstring_t xerrno_name(x_int32_t xit_errno)
    {
        x_cstring_t xszt_name = "";

        switch (xit_errno)
        {
        //======================================
        // open() 接口产生的错误码

        case X_ERR_BAD_ARGS             : xszt_name = "X_ERR_BAD_ARGS"            ; break;
        case X_ERR_ENCODER_CREATE       : xszt_name = "X_ERR_ENCODER_CREATE"      ; break;
        case X_ERR_SETPARAM_AOT         : xszt_name = "X_ERR_SETPARAM_AOT"        ; break;
        case X_ERR_SETPARAM_SBR         : xszt_name = "X_ERR_SETPARAM_SBR"        ; break;
        case X_ERR_SETPARAM_CHANNEL     : xszt_name = "X_ERR_SETPARAM_CHANNEL"    ; break;
        case X_ERR_SETPARAM_CHNLORDER   : xszt_name = "X_ERR_SETPARAM_CHNLORDER"  ; break;
        case X_ERR_SETPARAM_SAMPRATE    : xszt_name = "X_ERR_SETPARAM_SAMPRATE"   ; break;
        case X_ERR_SETPARAM_TRANSMUX    : xszt_name = "X_ERR_SETPARAM_TRANSMUX"   ; break;
        case X_ERR_SETPARAM_AFTERBURNER : xszt_name = "X_ERR_SETPARAM_AFTERBURNER"; break;
        case X_ERR_SETPARAM_BITRATEMODE : xszt_name = "X_ERR_SETPARAM_BITRATEMODE"; break;
        case X_ERR_SETPARAM_VBRMODE_1   : xszt_name = "X_ERR_SETPARAM_VBRMODE_1"  ; break;
        case X_ERR_SETPARAM_BITRATE     : xszt_name = "X_ERR_SETPARAM_BITRATE"    ; break;
        case X_ERR_ENCODE_FIRSTINIT     : xszt_name = "X_ERR_ENCODE_FIRSTINIT"    ; break;
        case X_ERR_GET_ENCODER_INFO     : xszt_name = "X_ERR_GET_ENCODER_INFO"    ; break;

        //======================================
        // encode() 接口产生的错误码

        case X_ERR_ENCODE_UNOPEN        : xszt_name = "X_ERR_ENCODE_UNOPEN"       ; break;
        case X_ERR_ENCODE_BADARGS       : xszt_name = "X_ERR_ENCODE_BADARGS"      ; break;
        case X_ERR_ENCODE_FAILED        : xszt_name = "X_ERR_ENCODE_FAILED"       ; break;

        //======================================
        default: break;
        }

        return xszt_name;
    }

    /**********************************************************/
    /**
     * @brief 获取 xerrno_table_t 中的错误码名称。
     */
    static x_cstring_t xerrno_name(x_errno_t xerr_no)
    {
        return xerrno_name(XERR_HINO(xerr_no));
    }

    // constructor/destructor
public:
    aac_encoder_t(void);
    ~aac_encoder_t(void);

    // public interfaces
public:
    /**********************************************************/
    /**
     * @brief 打开 AAC 编码器对象。
     * @note
     * 1. xut_bitrate :
     *   1.1 若为 0 时，则默认使用可变位速 XAAC_ENC_VBRMODE_1 模式；
     *   1.2 若 xut_enconfig 指定了 XAAC_ENC_VBRMODE，该参数被忽略。
     * 2. xut_enconfig : 使用 xaac_enc_config_t 中的枚举值进行组合。
     * 
     * @param [in ] xut_channels : 音频通道数。
     * @param [in ] xut_samprate : 音频采样率。
     * @param [in ] xut_enconfig : 编码操作使用的配置参数。
     * @param [in ] xut_bitrate  : 编码输出的位速。
     * 
     * @return x_errno_t : 错误码。
     * @retval X_ERR_OK, 操作成功。
     * @retval XERR_HINO(xerr_no)，参看 xerrno_table_t 相关枚举值。
     * @retval XERR_LONO(xerr_no)，所引用的模块返回的错误码值。
     */
    x_errno_t open(
                x_uint16_t xut_channels,
                x_uint32_t xut_samprate,
                x_uint32_t xut_enconfig = XAAC_ENC_DEFAULT,
                x_uint32_t xut_bitrate  = 0);

    /**********************************************************/
    /**
     * @brief 关闭 AAC 编码器对象。
     */
    x_void_t close(void);

    /**********************************************************/
    /**
     * @brief 判断当前编码器对象是否已经打开。
     */
    inline x_bool_t is_open(void) const
    {
        return (X_NULL != m_xht_encoder);
    }

    /**********************************************************/
    /**
     * @brief 编码操作的每帧音频数据长度。
     */
    inline x_uint32_t frame_len(void) const
    {
        return m_xut_framelen;
    }

    /**********************************************************/
    /**
     * @brief 返回当前编码器操作的通道数。
     */
    x_uint16_t channels(void) const;

    /**********************************************************/
    /**
     * @brief 返回当前编码器使用的编码采样率。
     */
    x_uint32_t sample_rate(void) const;

    /**********************************************************/
    /**
     * @brief 执行 PCM-S16 音频数据编码操作。
     * @note 
     * 输入的音频帧 xbuf_pcm 缓存，分为如下两种情况：
     *   1. (X_NULL != xbuf_pcm)，数据字节数为 frame_len()，
     *      不足时，可用 0 填充。
     *   2. (X_NULL == xbuf_pcm)，数据字节数为 0 。
     * 
     * @param [out   ] xbuf_aac : 输出编码后的音频数据所使用的缓存。
     * @param [in,out] xut_size : 入参，xbuf_aac 缓存大小；
     *                            回参，输出编码后的有效数据大小。
     * @param [in    ] xbuf_pcm : 输入的 PCM-S16 音频帧数据。
     * 
     * @return x_errno_t : 错误码。
     * @retval X_ERR_OK, 操作成功。
     * @retval XERR_HINO(xerr_no)，参看 xerrno_table_t 相关枚举值。
     * @retval XERR_LONO(xerr_no)，所引用的模块返回的错误码值。
     */
    x_errno_t encode(
        xaacbuf_t xbuf_aac, x_uint32_t & xut_size, cpcmbuf_t xbuf_pcm);

    // data members
protected:
    x_handle_t m_xht_encoder;  ///< ACC 编码器对象的操作句柄
    x_uint32_t m_xut_framelen; ///< 每帧可容纳的音频数据长度
};

////////////////////////////////////////////////////////////////////////////////
// aac_decoder_t

/**
 * @enum  xaac_dec_tmux_t
 * @brief 解码操作使用的配置参数枚举值。
 */
typedef enum xaac_dec_tmux_t
{
    XAAC_DEC_TMUXMP4_RAW   = 0x00000000,  ///< "as is" access units
    XAAC_DEC_TMUXMP4_ADIF  = 0x00000001,  ///< ADIF bitstream format.
    XAAC_DEC_TMUXMP4_ADTS  = 0x00000002,  ///< ADTS bitstream format.
    XAAC_DEC_TMUXMP4_MCP1  = 0x00000006,  ///< Audio Mux Elements with muxConfigPresent = 1
    XAAC_DEC_TMUXMP4_MCP0  = 0x00000007,  ///< Audio Mux Elements with muxConfigPresent = 0
    XAAC_DEC_TMUXMP4_LOAS  = 0x0000000A,  ///< Audio Sync Stream.
    XAAC_DEC_TMUXMP4_DRM   = 0x0000000C,  ///< Digital Radio Mondial (DRM30/DRM+) bitstream format.

    XAAC_DEC_DEFAULT = XAAC_DEC_TMUXMP4_ADTS
} xaac_dec_tmux_t;

/**
 * @enum  xaac_dec_flag_t
 * @brief 解码操作的 组合标识 枚举值。
 */
typedef enum xaac_dec_flag_t
{
    XAAC_DEC_CONCEAL = 0x00000001,  ///< Do concealment.
    XAAC_DEC_FLUSH   = 0x00000002,  ///< Discard input data. Flush filter banks (output delayed audio).
    XAAC_DEC_INTR    = 0x00000004,  ///< Input data is discontinuous. Resynchronize any internals as necessary.
    XAAC_DEC_CLRHIST = 0x00000008,  ///< Clear all signal delay lines and history buffers.
} xaac_dec_flag_t;

/**
 * @class aac_decoder_t
 * @brief 封装 FDK-AAC 的 API，实现 AAC 解码输出 PCM-S16 音频数据的操作。
 */
class aac_decoder_t
{
    // common data types
public:
    typedef x_byte_t  *      xaacbuf_t;
    typedef const xaacbuf_t  caacbuf_t;
    typedef x_int16_t *      xpcmbuf_t;
    typedef const xpcmbuf_t  cpcmbuf_t;

    /**
     * @enum  xerrno_table_t
     * @brief 错误码表。
     */
    typedef enum xerrno_table_t
    {
        //======================================
        // open() 接口产生的错误码

        X_ERR_TMUX_UNKNOW    = 0x00000001,  ///< 使用了未知的解码类型参数
        X_ERR_CREATE_DECODER = 0x00000002,  ///< 创建解码器对象失败
        X_ERR_CONFRAW_FAILED = 0x00000003,  ///< 配置 RAW 格式流信息失败

        //======================================
        // decode() 接口产生的错误码

        X_ERR_DECODE_UNOPEN  = 0x00000041,  ///< 解码器对象未打开
        X_ERR_DECODE_BADARGS = 0x00000042,  ///< 输入的参数错误
        X_ERR_DECODE_FILLAAC = 0x00000051,  ///< 填充 AAC 音频缓存数据时，操作失败
        X_ERR_DECODE_FAILED  = 0x00000052,  ///< 解码操作失败

        //======================================
    } xerrno_table_t;

    // common invoking
public:
    /**********************************************************/
    /**
     * @brief 获取 xerrno_table_t 中的错误码名称。
     */
    static x_cstring_t xerrno_name(x_int32_t xit_errno)
    {
        x_cstring_t xszt_name = "";

        switch (xit_errno)
        {
        //======================================
        // open() 接口产生的错误码

        case X_ERR_TMUX_UNKNOW    : xszt_name = "X_ERR_TMUX_UNKNOW"   ; break;
        case X_ERR_CREATE_DECODER : xszt_name = "X_ERR_CREATE_DECODER"; break;
        case X_ERR_CONFRAW_FAILED : xszt_name = "X_ERR_CONFRAW_FAILED"; break;

        //======================================
        // decode() 接口产生的错误码

        case X_ERR_DECODE_UNOPEN  : xszt_name = "X_ERR_DECODE_UNOPEN" ; break;
        case X_ERR_DECODE_BADARGS : xszt_name = "X_ERR_DECODE_BADARGS"; break;
        case X_ERR_DECODE_FILLAAC : xszt_name = "X_ERR_DECODE_FILLAAC"; break;
        case X_ERR_DECODE_FAILED  : xszt_name = "X_ERR_DECODE_FAILED" ; break;

        //======================================
        default: break;
        }

        return xszt_name;
    }

    /**********************************************************/
    /**
     * @brief 获取 xerrno_table_t 中的错误码名称。
     */
    static x_cstring_t xerrno_name(x_errno_t xerr_no)
    {
        return xerrno_name(XERR_HINO(xerr_no));
    }

    // constructor/destructor
public:
    aac_decoder_t(void);
    ~aac_decoder_t(void);

    // public interfaces
public:
    /**********************************************************/
    /**
     * @brief 打开解码器对象。
     * 
     * @param [in ] xit_tmux : 解码操作的 AAC 音频数据类型（参看 xaac_dec_tmux_t）。
     * @param [in ] xct_conf : 解码 RAW-AAC 格式时，使用的带外数据。
     * @param [in ] xut_size : xct_conf 中各个缓存的有效数据大小。
     * 
     * @return x_errno_t : 错误码。
     * @retval X_ERR_OK, 操作成功。
     * @retval XERR_HINO(xerr_no)，参看 xerrno_table_t 相关枚举值。
     * @retval XERR_LONO(xerr_no)，所引用的模块返回的错误码值。
     */
    x_errno_t open(
                x_int32_t   xit_tmux = XAAC_DEC_DEFAULT,
                x_uchar_t * xct_conf[] = X_NULL,
                x_uint32_t  xut_size[] = X_NULL);

    /**********************************************************/
    /**
     * @brief 关闭解码器对象。
     */
    x_void_t close(void);

    /**********************************************************/
    /**
     * @brief 判断当前解码器对象是否已经打开。
     */
    inline x_bool_t is_open(void) const
    {
        return (X_NULL != m_xht_decoder);
    }

    /**********************************************************/
    /**
     * @brief 返回当前解码的数据中 音频的编码对象类型（返回 0 时，表示未知）。
     * @note 参看 xaac_aot_t 相关枚举值。
     */
    x_int32_t aot(void) const;

    /**********************************************************/
    /**
     * @brief 返回当前解码的数据中 音频的通道数（返回 0 时，表示未知）。
     */
    x_uint16_t channels(void) const;

    /**********************************************************/
    /**
     * @brief 返回当前解码的数据中 音频的采样率（返回 0 时，表示未知）。
     */
    x_uint32_t sample_rate(void) const;

    /**********************************************************/
    /**
     * @brief 返回当前解码的每帧音频数据长度（返回 0 时，表示未知）。
     */
    x_uint32_t frame_len(void) const;

    /**********************************************************/
    /**
     * @brief 清理解码器缓存。
     */
    x_void_t cleanup(void);

    /**********************************************************/
    /**
     * @brief 执行解码操作。
     * 
     * @param [out   ] xbuf_pcm : 输出解码后的 PCM-S16 音频数据所使用的缓存。
     * @param [in,out] xut_plen : 入参，xbuf_pcm 缓存大小（按字节计数）；
     *                            回参，xbuf_pcm 中有效数据长度（按字节计数）。
     * @param [in    ] xbuf_aac : 输入待解码的 AAC 音频数据的缓存。
     * @param [in,out] xut_alen : 入参，xbuf_aac 缓存中有效数据长度（按字节计数）；
     *                            回参，xbuf_aac 剩余的（未输入到解码器缓存的）字节数。
     * @param [in    ] xut_flag : 解码操作的 组合标识 值（参看 xaac_dec_flag_t）。
     * 
     * @return x_errno_t : 错误码。
     * @retval X_ERR_OK, 操作成功。
     * @retval XERR_HINO(xerr_no)，参看 xerrno_table_t 相关枚举值。
     * @retval XERR_LONO(xerr_no)，所引用的模块返回的错误码值。
     */
    x_errno_t decode(
        xpcmbuf_t    xbuf_pcm,
        x_uint32_t & xut_plen,
        caacbuf_t    xbuf_aac,
        x_uint32_t & xut_alen,
        x_uint32_t   xut_flag = 0);

    // data members
protected:
    x_handle_t   m_xht_decoder;  ///< ACC 解码器对象的操作句柄
};

////////////////////////////////////////////////////////////////////////////////

#endif // __AUDIO_AAC_H__

